package com.ld.hpfs.common.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
//import java.io.ObjectInputStream;
import java.io.Reader;
//import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
//import java.net.URLDecoder;
import java.security.Key;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ld.hpfs.common.jackson.JackJson;

import javax.crypto.Cipher;

//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;

//import com.ld.hpfs.web.controller.MainController;

import sun.misc.BASE64Decoder;

//用户解密流程：调用密文读取API(User_Message())-->调用公钥读取(RSA())-->RSA分支：调用BASE64解密密文(decryptBASE64())-->RSA分支：调用RSA解密密文(decrypt())-->User_Message()分支：返回解密用户信息字符串(User_Message())

public class RsaDecrypt {
		
	private String readFileByChars(String fileName) {
        File file = new File(fileName);
        Reader reader = null;
        char[] tempchars = new char[1024];
        String MSG = "";
        try {
         if (file!=null) {
           // 一次读多个字符
//                char[] tempchars = new char[30];
                int charread = 0;
                try{
                	reader = new InputStreamReader(new FileInputStream(fileName));
                }catch (Exception ex){
//                	System.out.println("NO FILE");
                	return "NO FILE";
                }
                // 读入多个字符到字符数组中，charread为一次读取字符数
                while ((charread = reader.read(tempchars)) != -1) {
                    // 同样屏蔽掉\r不显示
                    if ((charread == tempchars.length)
                            && (tempchars[tempchars.length - 1] != '\r')) {
                        System.out.print(tempchars);
                    } else {
                        for (int i = 0; i < charread; i++) {
                            if (tempchars[i] == '\r') {
                                continue;
                            } else {
                                System.out.print(tempchars[i]);
                                MSG += tempchars[i];
                            }
                        }
                    }
                }
         	}
        } catch (Exception e1) {
//        	return "NO FILE";
            e1.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
//                   System.out.println("文件不存在");
//                   return "NO FILE";
                	e1.printStackTrace();
                }
            }
        }
//        System.out.println("File: "+tempchars);
        return MSG;
    }

		/**
		 * @author LZQ
		 * @param 
		 * @return 解密的String字符串信息
		 * 此程序先读取被BASE64加密的RSA加密信息，然后先解密BASE64，接着根据解密的字符串决定是否需要分段解密RSA信息，最后返回解密的字符串。
		 */
	private String User_Message() throws Exception {  //获取解密后的用户信息
//TEST_PK为写死的BASE加密后的用户信息文件，修改的话使用readFromFile()进行读取，可能里面的ObjectInputStream要修改成Reader
		/*正式版：BASE64加密文件中的加密字符串*/
//		String Path = getClass().getResource("/").toString();//E:\南京乐达(上海瑞想)\IT Work Space\Spring Tool Suite\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\HPFS\WEB-INF\classes
		String User_Licences_Files = Const.PROPERTIES.getProperty("import.user_licences", "d:\\User_Licences\\");  //从src/main/resources/config/other/config.properties获取
		String Security_Message = this.readFileByChars(User_Licences_Files + "./hitpoint.lic");
		if(Security_Message == "NO FILE"){
			return "NO FILE";
		}
		String MSG = "";
		try {
			/*正式版：解密(BASE64->RSA)*/
			MSG = RSA(Security_Message);  //解密信息，MSG为最后的解密信息，终于经过：BASE64解密用户信息得到密文-->RSA解密用户密文(搭配公钥)
//			System.out.println("MSG: "+MSG);
			return MSG;
		}catch (Exception e){
			e.printStackTrace();
		}
		return MSG;
	}
	public String getTime() throws Exception{ //获取license到期时间
		Map<String, Object> User_Licences = JackJson.fromJsonToObject(User_Message(), Map.class);
		String expried = User_Licences.get("ExpiredDate").toString(); 
		return expried;
		
	}
	
	public String getCustomer() throws Exception{ //获取license到期时间
		Map<String, Object> User_Licences = JackJson.fromJsonToObject(User_Message(), Map.class);
		String customer = User_Licences.get("Customer").toString(); 
		return customer;
		
	}
	
	public long LoginTime() throws Exception {  //判断登录时间
		//User_Message()返回值为解密的用户文件
//		String TIME1 = User_Message().split(" ",5)[4].substring(0,10);  //截取字符串，得到"yyyy-MM-dd"格式时间
//		String TIME1 = User_Message().split(" ",5)[3].substring(1,11);
		if(User_Message() == "NO FILE"){
			return -2;  //当读取用户密钥文件失败，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		if(User_Message() == "ERROR FILE"){
			return -3;  //当用户密钥文件解密失败，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		Map<String, Object> User_Licences = JackJson.fromJsonToObject(User_Message(), Map.class);  //将JSON转为OBJECT
		String Version_Licenses = User_Licences.get("Products").toString();
		Pattern p = Pattern.compile("T6.1");
		Matcher m = p.matcher(Version_Licenses);
//		if(!Version_Licenses.equals("[T6.1]")){
		if(!m.find()){
			return -4;//当用户密钥文件版本不正确，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		String TIME1 = User_Licences.get("ExpiredDate").toString();  //根据JSON对象中的变量名提取对应的值并转为STRING格式
//		System.out.println(TIME3);
//		String TIME1 = "2013-02-24";   //TEST USER LIENCE TIME		
		Date date = new Date();
		SimpleDateFormat from = new SimpleDateFormat("yyyy-MM-dd"); //获取服务器时间并格式化，格式为"yyyy-MM-dd"
		String SYSTIME = from.format(date);   //SYSTEM TIME
		
		Date Begin = from.parse(TIME1);   //USER LIENCE TIME
		Date End = from.parse(SYSTIME); //SERVER TIME
		long between = (Begin.getTime()-End.getTime())/1000;   //用户时间 - 服务器时间 = 证书可用时间
		long Day = between/(24*3600);   //时间单位转换为天
		if(End.after(Begin)){  //超出时间：服务器时间超出用户时间(服务器时间 - 用户文件时间 < 0)
//			System.out.println("您的证书已过期，禁止登陆");
			return -1;
		}
		return Math.abs(Day);  //可以登录，但是否提示证书过期，就需要在LoginController.java处接收return的地方判断
	}

	public String Company_Number() throws Exception {  //获取公司数量
//		String Now_Company_Num = User_Message().split(" ",14)[13];  //截取获得用户信息文件中的公司数量
//		String company_temp = User_Message().split(":",7)[6];
		if(User_Message() == "NO FILE"){
			return "NO FILE";  //当读取用户密钥文件失败，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		if(User_Message() == "ERROR FILE"){
			return "ERROR FILE";  //当用户密钥文件解密失败，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		Map<String, Object> User_Licences = JackJson.fromJsonToObject(User_Message(), Map.class);
		String company_temp = User_Licences.get("CompanyNumber").toString();  //获取JSON指定串
//		String Now_Company_Num = company_temp.substring(0,company_temp.length()-1);
//		return Now_Company_Num;
		return company_temp;
	}
	
	public String User_Number() throws Exception {   //获取用户数量
//		String Now_User_Num = User_Message().split(" ",11)[10].split(": ",2)[1].split(",",2)[0];  //截取获得用户信息文件中的用户数量
//		String user_temp = User_Message().split(" ",11)[10].split(": ",2)[1].split(",",2)[0];
		if(User_Message() == "NO FILE"){
			return "NO FILE";  //当读取用户密钥文件失败，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		if(User_Message() == "ERROR FILE"){
			return "ERROR FILE";  //当用户密钥文件解密失败，则禁止登陆，但是只做此安全条件设置，不做用户/公司数量安全设置
		}
		Map<String, Object> User_Licences = JackJson.fromJsonToObject(User_Message(), Map.class);
		String user_temp = User_Licences.get("UserNumber").toString();
//		String Now_User_Num = user_temp.substring(0,user_temp.length());
//		return Now_User_Num;
		return user_temp;
	}
	
	private String RSA(String PassMessage) throws Exception {//解密用户文件函数。其参数：用户密文(密文之前未被BASE64解密)
		// TODO Auto-generated method stub
		//读取公钥		
		/*TEST&正式版:互质数字符串*/
		String PUB_Exponent = "65537";
		/*正式版：公钥字符串*/
		String PUB_KEY = "91506901750097032150672799291192929946483313589596907625428285496146391223717222245654329146900415753576882856818606106558970509175668833321835605306074208606820389443594419436386321499205589144165558519114878918046167929527963199678519074060815934433201070178030150616356053914711758710035301718064331084259";
		/*正式版：公钥大素数*/
		BigInteger m = new BigInteger(PUB_KEY);	
		BigInteger e = new BigInteger(PUB_Exponent);  //互质数大整型
		RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m,e);   
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);		//根据素数+互质数得到真正的RSAPublicKey
		
		String M2 = toHexString(decryptBASE64(PassMessage)); //BASE64解密用户密文(经过此步才能进行RSA解密)
//		byte[] M2 = (new BASE64Decoder()).decodeBuffer(PassMessage); //NEW BASE64
		/**
		 * BASE64解密测试，DEBUG使用
		 */
//		System.out.println("DATA-A: "+new String(decryptBASE64(PassMessage))); 
//		System.out.println("DATA-B: "+M2);
//		System.out.println("Public Key: "+publicKey);
        
		String MSG = decrypt(M2,publicKey);
		
//		System.out.println("MSG: "+MSG);
		
		return MSG; //最后返回解密的信息
	}

	private String decrypt(String message, Key key) throws Exception { //RSA解密，之前已解密BASE64
		// TODO Auto-generated method stub
		/*兼容：128短位解密
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, key);
		return cipher.doFinal(toBytes(message));
*///增强：128&128+位解密

		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, key);

		int mLen = toBytes(message).length;
		int sLen = message.length();
		byte[] target = toBytes(message);
		int EMAX = 128;
//		System.out.println("DmLen2: "+mLen);
//		System.out.println("DmLen2S: "+sLen);
		int Blocks = mLen / 128;
		if(mLen % 128 !=0){Blocks += 1;}
//		System.out.println("Blocks-D: "+Blocks);
		byte[] temp = new byte[128];
		byte[] result = new byte[Blocks * 128];
		String RESULT = "";
		
		if(mLen > 128){
//			System.out.println("分段加密");
			for(int i=0;i<Blocks;i++){
				System.arraycopy(target, i*128, temp, 0, 128);
				byte[] temp2 = new byte[128];
				try{
					temp2 = cipher.doFinal(temp);
				}catch (Exception ex){
//					System.out.println("用户密钥文件错误，禁止登陆");
					return "ERROR FILE";
				}
//				System.out.println("D: "+new String(temp));
//				System.out.println("D-len: "+temp.length);
//				System.out.println("D2: "+new String(temp2));
//				System.out.println("D2-len: "+temp2.length);
//				System.out.println("Result-String-D: "+new String(temp2));
				System.arraycopy(temp2, 0, result, i*128, temp2.length);
				RESULT += new String(temp2);
			}
		}else{
//			System.out.println("直接加密");
//			return cipher.doFinal(target);
			try{
				return new String(cipher.doFinal(target));
			}catch (Exception ex){
//				System.out.println("用户密钥文件错误，禁止登陆");
				return "ERROR FILE";
			}
		}
//		return result;
		return RESULT;
	}

	private byte[] toBytes(String s) {  //数据转2进制
		// TODO Auto-generated method stub
		byte[] bytes;
		bytes = new byte[s.length() / 2];
		for (int i = 0; i < bytes.length; i++) {
			bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2),16);
		}
		return bytes;
	}

	private char[] HEXCHAR = { '0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	
	private String toHexString(byte[] b) {  //数据转16进制
		// TODO Auto-generated method stub
		StringBuilder sb = new StringBuilder(b.length * 2);
		for (int i = 0; i < b.length; i++) {
		sb.append(HEXCHAR[(b[i] & 0xf0) >>> 4]);
		sb.append(HEXCHAR[b[i] & 0x0f]);
		}
		return sb.toString();
	}
	private byte[] decryptBASE64(String key) throws Exception {//BASE64解密
		// TODO Auto-generated method stub
		return (new BASE64Decoder()).decodeBuffer(key);  //返回已经BASE64解密的用户信息(此时RSA仍然处于加密状态)
	}
}
